package cn.xzqwjw.taskmanager.service.impl;

import cn.xzqwjw.taskmanager.common.customEnum.ResponseCodeEnum;
import cn.xzqwjw.taskmanager.common.exception.CustomException;
import cn.xzqwjw.taskmanager.domain.pojo.SysFrontRoute;
import cn.xzqwjw.taskmanager.domain.vo.FrontMenuVo;
import cn.xzqwjw.taskmanager.domain.vo.ResponseVo;
import cn.xzqwjw.taskmanager.repository.SysFrontRouteMapper;
import cn.xzqwjw.taskmanager.service.SysFrontRouteService;
import cn.xzqwjw.taskmanager.utils.CommonUtil;
import cn.xzqwjw.taskmanager.utils.ConvertUtil;
import cn.xzqwjw.taskmanager.utils.JsonUtil;
import cn.xzqwjw.taskmanager.utils.ResponseUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @author rush
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class SysFrontRouteServiceImpl extends ServiceImpl<SysFrontRouteMapper, SysFrontRoute>
    implements SysFrontRouteService {

  private final SysFrontRouteMapper frontRouteMapper;

  @Autowired
  public SysFrontRouteServiceImpl(SysFrontRouteMapper frontRouteMapper) {
    this.frontRouteMapper = frontRouteMapper;
  }

  @Override
  public String add(SysFrontRoute frontRoute) {
    if (save(frontRoute)) {
      return JsonUtil.obj2Json(ResponseVo.success(ResponseCodeEnum.OK_CREATED));
    } else {
      throw new CustomException(ResponseCodeEnum.ERROR_INSERT);
    }
  }

  @Override
  public String delById(Integer id) {
    if (removeById(id)) {
      return JsonUtil.obj2Json(ResponseVo.success(ResponseCodeEnum.OK_DELETED));
    } else {
      throw new CustomException(ResponseCodeEnum.ERROR_DELETE);
    }
  }

  @Override
  public String modifyAll(SysFrontRoute frontRoute) {
    if (updateById(frontRoute)) {
      return JsonUtil.obj2Json(ResponseVo.success(ResponseCodeEnum.OK_UPDATED));
    } else {
      throw new CustomException(ResponseCodeEnum.ERROR_UPDATE);
    }
  }

  @Override
  public String queryById(Integer id) {
    SysFrontRoute frontRoute = getById(id);
    if (!Objects.isNull(frontRoute)) {
      return JsonUtil.obj2Json(ResponseVo.success(frontRoute));
    } else {
      throw new CustomException(ResponseCodeEnum.BAD_REQUEST);
    }
  }

  @Override
  public String listAll() {
    return JsonUtil.obj2Json(ResponseVo.success(list()));
  }

  @Override
  public List<SysFrontRoute> listAll4Menu() {
    QueryWrapper<SysFrontRoute> wrapper = new QueryWrapper<>();
    wrapper.orderByAsc("weight");
    return list(wrapper);
  }

  @Override
  public String listPage(Integer pageCurrent, Integer pageSize) {
    Page<Map<String, Object>> pager = CommonUtil.getPage(pageCurrent, pageSize);
    List<Map<String, Object>> listData = frontRouteMapper.listPage(pager).getRecords();
    return ResponseUtil.writePageData(pager, listData, pageSize);
  }

  @Override
  public Map<String, Object> setMenu(List<SysFrontRoute> allRouteList, boolean isSuperAdmin) {
    // 传进来的路由是某位管理员下的所拥有的权限能对应到的所有路由
    // 如果不是超级管理员，传进来的路由只是该管理员所拥有的权限所对应的路由，要先加上父路由
    // 如果是超级管理员，传进来的路由是直接从路由表里得到的所有路由，就不需要再加父路由
    if (!isSuperAdmin) {
      allRouteList = getRootRoute(allRouteList);
    }
    if (Objects.isNull(allRouteList)) {
      return null;
    }
    List<SysFrontRoute> rootRouterList = new ArrayList<>();
    // 先找到所有的一级菜单
    for (SysFrontRoute router : allRouteList) {
      // 一级菜单 idParent==1
      if (router.getIdParent() == 1) {
        rootRouterList.add(router);
      }
    }
    // intA.compareTo(intB)
    // 如果intA与intB相等返回0 如果intA小于intB返回 -1 如果intA大于intB返回 1
    rootRouterList.sort((SysFrontRoute r1, SysFrontRoute r2) ->
        r2.getWeight().compareTo(r1.getWeight())
    );
    // 为一级菜单设置子菜单，getChild是递归调用
    for (SysFrontRoute router : rootRouterList) {
      router.setChildRouterList(getChildRouteList(router.getId(), allRouteList));
    }
    // 将router转成menu
    List<FrontMenuVo> menuList = new ArrayList<>();
    for (SysFrontRoute router : rootRouterList) {
      menuList.add(setRouteToMenu(router));
    }
    Map<String, Object> jsonMap = new HashMap<>(16);
    jsonMap.put("menu", menuList);
    return jsonMap;
  }

  /**
   * 递归将路由转成menu
   *
   * @param route 要转换的路由
   * @return FrontMenuDto 菜单
   */
  private FrontMenuVo setRouteToMenu(SysFrontRoute route) {
    FrontMenuVo menu = new FrontMenuVo();
    menu.setName(route.getRouteName());
    menu.setPath(route.getClientUrl());
    menu.setRedirect(route.getRedirect());
    menu.setComponent(route.getComponentPath());
    menu.setFlagShowLeft(route.getFlagShowLeft());
    Map<String, String> metaDataMap = new HashMap<>(16);
    metaDataMap.put("title", route.getTitle());
    metaDataMap.put("icon", route.getIcon());
    menu.setMeta(metaDataMap);
    menu.setFlagHidden(route.getFlagHidden());
    menu.setWeight(route.getWeight());
    if (Objects.nonNull(route.getChildRouterList())) {
      List<FrontMenuVo> listMenu = new ArrayList<>();
      for (SysFrontRoute frontRoute : route.getChildRouterList()) {
        listMenu.add(setRouteToMenu(frontRoute));
      }
      menu.setChildren(listMenu);
    } else {
      menu.setChildren(null);
    }
    return menu;
  }

  /**
   * 递归查找某个id下的子路由
   *
   * @param id            要查找的id
   * @param rootRouteList 要查找的路由列表
   * @return List<SysFrontRouter> 路由列表
   */
  private List<SysFrontRoute> getChildRouteList(Integer id, List<SysFrontRoute> rootRouteList) {
    // 得到某id下的所有子路由
    List<SysFrontRoute> childRouteList = new ArrayList<>();
    for (SysFrontRoute route : rootRouteList) {
      // 遍历所有节点，将父id与传过来的id比较
      if (route.getIdParent().equals(id)) {
        childRouteList.add(route);
      }
    }
    // 递归退出条件
    if (childRouteList.isEmpty()) {
      return null;
    }
    childRouteList.sort((SysFrontRoute r1, SysFrontRoute r2) ->
        r2.getWeight().compareTo(r1.getWeight())
    );
    // 把子路由的子路由再循环一遍
    for (SysFrontRoute route : childRouteList) {
      // 递归调用本身函数，继续设置子路由
      route.setChildRouterList(getChildRouteList(route.getId(), rootRouteList));
    }
    return childRouteList;
  }

  /**
   * 将每个router的所有父元素加入到list中
   *
   * @param listRoute 某管理员所拥有的所有权限所对应的所有路由
   * @return 包含每个路由的父路由的list
   */
  private List<SysFrontRoute> getRootRoute(List<SysFrontRoute> listRoute) {
    if (Objects.isNull(listRoute)) {
      return null;
    }
    // System.out.println("传入的listRoute的长度是：" + listRoute.size());
    listRoute = ConvertUtil.clearRepeatList(listRoute);
    int parentId, level;
    SysFrontRoute parentRoute;
    List<SysFrontRoute> returnList = new ArrayList<>();
    for (SysFrontRoute route : listRoute) {
      returnList.add(route);
      level = route.getLevel();
      parentId = route.getIdParent();
      for (int i = 1; i < level; i++) {
        parentRoute = getById(parentId);
        returnList.add(parentRoute);
        parentId = parentRoute.getIdParent();
      }
    }
    // System.out.println("传出的returnList的长度是：" + returnList.size());
    return ConvertUtil.clearRepeatList(returnList);
  }

}
